//    Time Surfer
//    Copyright (C) 2008  Gaian Mystery School
//    http://www.gaianmysteryschool.com
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>

#import "Dreamspell.h"

#define BASEYEAR 1987
#define STARTYEAR 8
#define STARTSEAL 14

@interface Dreamspell (Private)

- (void)yearmore:(int)year;
- (void)yearless:(int)year;
- (void)dropyear;

@end

@implementation Dreamspell

int months[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 
char *sseal[]={"Sun","Dragon","Wind","Night","Seed","Serpent","World-Bridger","Hand","Star","Moon","Dog","Monkey","Human","Skywalker","Wizard","Eagle","Warrior","Earth","Mirror","Storm"}; 
char *color[]={"Yellow","Red","White","Blue","Yellow","Red","White","Blue","Yellow","Red","White","Blue","Yellow","Red","White","Blue","Yellow","Red","White","Blue"};
char *tone[]={"","Magnetic","Lunar","Electric","Self-Existing","Overtone","Rhythmic","Resonant","Galactic","Solar","Planetary","Spectral","Crystal","Cosmic"}; 
char *poemseal[]={"Enlighten", "Nurture", "Communicate", "Dream", "Target", "Survive", "Equalize", "Know", "Beautify", "Purify", "Love", "Play", "Influence", "Explore", "Enchant", "Create", "Question", "Evolve", "Reflect", "Catalyse"}; 
char *poemseal2[]={"Life", "Being", "Breath", "Intuition", "Awareness", "Instinct", "Opportunity", "Healing", "Art", "Flow", "Loyalty", "Illusion", "Wisdom", "Wakefullness", "Receptivity", "Mind", "Fearlessness", "Synchronicity", "Order", "Energy"}; 
char *poemseal3[]={"Matrix", "Input", "Input", "Input", "Input", "Store", "Store", "Store", "Store", "Process", "Process", "Process", "Process", "Output", "Output", "Output", "Output", "Matrix", "Matrix", "Matrix"}; 
char *poemseal4[]={"Universal Fire", "Birth", "Spirit", "Abundance", "Flowering", "Life Force", "Death", "Accomplishment", "Elegance", "Universal Water", "Heart", "Magic", "Free Will", "Space", "Timelessness", "Vision", "Intelligence", "Navigation", "Endlessness", "Self-generation"}; 
char *toneseal[]={"0","Unify", "Polarize", "Activate", "Define", "Empower", "Organize", "Channel", "Harmonize", "Pulse", "Perfect", "Dissolve", "Dedicate", "Endure"}; 
char *toneseal2[]={"0","Attracting", "Stabilizing", "Bonding", "Measuring", "Commanding", "Balancing", "Inspiring", "Modeling", "Realizing", "Producing", "Releasing", "Universalizing", "Transcending"}; 
char *toneseal3[]={"0","Purpose", "Challenge", "Service", "Form", "Radiance", "Equality", "Attunement", "Integrity", "Intention", "Manifestation", "Liberation", "Cooperation", "Presence"}; 

int pacalAuspiciousDays[]={20,26,30,40,57,58,60,87,106,132,176,211,245};
int toneoccult[]={0,13,12,11,10,9,8,7,6,5,4,3,2,1};

int tzolkinMatrix[20][13]=
{
	{1, 21, 41, 61, 81, 101, 121, 141, 161, 181, 201, 221, 241}, 
	{2, 22, 42, 62, 82, 102, 122, 142, 162, 182, 202, 222, 242}, 
	{3, 23, 43, 63, 83, 103, 123, 143, 163, 183, 203, 223, 243}, 
	{4, 24, 44, 64, 84, 104, 124, 144, 164, 184, 204, 224, 244}, 
	{5, 25, 45, 65, 85, 105, 125, 145, 165, 185, 205, 225, 245}, 
	{6, 26, 46, 66, 86, 106, 126, 146, 166, 186, 206, 226, 246}, 
	{7, 27, 47, 67, 87, 107, 127, 147, 167, 187, 207, 227, 247}, 
	{8, 28, 48, 68, 88, 108, 128, 148, 168, 188, 208, 228, 248}, 
	{9, 29, 49, 69, 89, 109, 129, 149, 169, 189, 209, 229, 249}, 
	{10, 30, 50, 70, 90, 110, 130, 150, 170, 190, 210, 230, 250}, 
	{11, 31, 51, 71, 91, 111, 131, 151, 171, 191, 211, 231, 251}, 
	{12, 32, 52, 72, 92, 112, 132, 152, 172, 192, 212, 232, 252}, 
	{13, 33, 53, 73, 93, 113, 133, 153, 173, 193, 213, 233, 253}, 
	{14, 34, 54, 74, 94, 114, 134, 154, 174, 194, 214, 234, 254}, 
	{15, 35, 55, 75, 95, 115, 135, 155, 175, 195, 215, 235, 255}, 
	{16, 36, 56, 76, 96, 116, 136, 156, 176, 196, 216, 236, 256}, 
	{17, 37, 57, 77, 97, 117, 137, 157, 177, 197, 217, 237, 257}, 
	{18, 38, 58, 78, 98, 118, 138, 158, 178, 198, 218, 238, 258}, 
	{19, 39, 59, 79, 99, 119, 139, 159, 179, 199, 219, 239, 259}, 
	{20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260}
};


int toneMatrix[20][13]=
{
	{1, 8, 2, 9, 3, 10, 4, 11, 5, 12, 6, 13, 7}, 
	{2, 9, 3, 10, 4, 11, 5, 12, 6, 13, 7, 1, 8}, 
	{3, 10, 4, 11, 5, 12, 6, 13, 7, 1, 8, 2, 9}, 
	{4, 11, 5, 12, 6, 13, 7, 1, 8, 2, 9, 3, 10}, 
	{5, 12, 6, 13, 7, 1, 8, 2, 9, 3, 10, 4, 11}, 
	{6, 13, 7, 1, 8, 2, 9, 3, 10, 4, 11, 5, 12}, 
	{7, 1, 8, 2, 9, 3, 10, 4, 11, 5, 12, 6, 13}, 
	{8, 2, 9, 3, 10, 4, 11, 5, 12, 6, 13, 7, 1}, 
	{9, 3, 10, 4, 11, 5, 12, 6, 13, 7, 1, 8, 2}, 
	{10, 4, 11, 5, 12, 6, 13, 7, 1, 8, 2, 9, 3}, 
	{11, 5, 12, 6, 13, 7, 1, 8, 2, 9, 3, 10, 4}, 
	{12, 6, 13, 7, 1, 8, 2, 9, 3, 10, 4, 11, 5}, 
	{13, 7, 1, 8, 2, 9, 3, 10, 4, 11, 5, 12, 6}, 
	{1, 8, 2, 9, 3, 10, 4, 11, 5, 12, 6, 13, 7}, 
	{2, 9, 3, 10, 4, 11, 5, 12, 6, 13, 7, 1, 8}, 
	{3, 10, 4, 11, 5, 12, 6, 13, 7, 1, 8, 2, 9}, 
	{4, 11, 5, 12, 6, 13, 7, 1, 8, 2, 9, 3, 10}, 
	{5, 12, 6, 13, 7, 1, 8, 2, 9, 3, 10, 4, 11}, 
	{6, 13, 7, 1, 8, 2, 9, 3, 10, 4, 11, 5, 12}, 
	{7, 1, 8, 2, 9, 3, 10, 4, 11, 5, 12, 6, 13}
};

int kinMatrix[20][13]=
{
	{1, 41, 81, 121, 161, 201, 241, 21, 61, 101, 141, 181, 221}, 
	{222, 2, 42, 82, 122, 162, 202, 242, 22, 62, 102, 142, 182}, 
	{183, 223, 3, 43, 83, 123, 163, 203, 243, 23, 63, 103, 143}, 
	{144, 184, 224, 4, 44, 84, 124, 164, 204, 244, 24, 64, 104}, 
	{105, 145, 185, 225, 5, 45, 85, 125, 165, 205, 245, 25, 65}, 
	{66, 106, 146, 186, 226, 6, 46, 86, 126, 166, 206, 246, 26}, 
	{27, 67, 107, 147, 187, 227, 7, 47, 87, 127, 167, 207, 247}, 
	{248, 28, 68, 108, 148, 188, 228, 8, 48, 88, 128, 168, 208}, 
	{209, 249, 29, 69, 109, 149, 189, 229, 9, 49, 89, 129, 169}, 
	{170, 210, 250, 30, 70, 110, 150, 190, 230, 10, 50, 90, 130}, 
	{131, 171, 211, 251, 31, 71, 111, 151, 191, 231, 11, 51, 91}, 
	{92, 132, 172, 212, 252, 32, 72, 112, 152, 192, 232, 12, 52}, 
	{53, 93, 133, 173, 213, 253, 33, 73, 113, 153, 193, 233, 13}, 
	{14, 54, 94, 134, 174, 214, 254, 34, 74, 114, 154, 194, 234}, 
	{235, 15, 55, 95, 135, 175, 215, 255, 35, 75, 115, 155, 195}, 
	{196, 236, 16, 56, 96, 136, 176, 216, 256, 36, 76, 116, 156}, 
	{157, 197, 237, 17, 57, 97, 137, 177, 217, 257, 37, 77, 117}, 
	{118, 158, 198, 238, 18, 58, 98, 138, 178, 218, 258, 38, 78}, 
	{79, 119, 159, 199, 239, 19, 59, 99, 139, 179, 219, 259, 39}, 
	{40, 80, 120, 160, 200, 240, 20, 60, 100, 140, 180, 220, 260}
};

int gapDays[]={1,241,22,222,43,203,64,184,85,165,106,146,107,147,88,108,148,168,69,109,149,189,50,110,150,210,51,111,151,211,72,112,152,192,93,113,153,173,114,154,115,155,96,176,77,197,58,218,39,239,20,260};

int gapMatrix[20][13]=
{
	{1,0,0,0,0,0,1,0,0,0,0,0,0},
	{1,0,0,0,0,0,0,0,1,0,0,0,0},
	{0,0,0,1,0,0,0,1,0,0,0,0,0},
	{0,1,0,0,0,0,0,0,0,0,0,1,0},
	{0,0,0,0,0,0,1,0,1,0,0,0,0},
	{0,1,1,0,0,0,0,0,0,0,0,0,0},
	{0,0,1,1,0,0,0,0,0,0,0,0,0},
	{0,0,0,1,1,0,0,0,0,1,0,1,0},
	{0,0,0,1,1,1,1,0,0,0,0,0,0},
	{0,1,0,0,0,1,1,0,0,0,1,0,0},
	{0,0,1,0,0,0,1,1,0,0,0,1,0},
	{0,0,0,0,0,0,1,1,1,1,0,0,0},
	{0,1,0,1,0,0,0,0,1,1,0,0,0},
	{0,0,0,0,0,0,0,0,0,1,1,0,0},
	{0,0,0,0,0,0,0,0,0,0,1,1,0},
	{0,0,0,0,1,0,1,0,0,0,0,0,0},
	{0,1,0,0,0,0,0,0,0,0,0,1,0},
	{0,0,0,0,0,1,0,0,0,1,0,0,0},
	{0,0,0,0,1,0,0,0,0,0,0,0,1},
	{0,0,0,0,0,0,1,0,0,0,0,0,1}
};

-(id)initWithDate:(int)month day:(int)day year:(int)year
{
	_year=STARTYEAR; 
	_seal=STARTSEAL; 

	if (year>BASEYEAR) 
		[self yearmore: year]; 
	if (year<BASEYEAR) 
		[self yearless: year]; 

	if (month<7) 
		[self dropyear]; 

	if ((month==7) && (day<26)) 
		[self dropyear]; 

	_yeartone=_year; 
	_yearseal=_seal; 
	_tone=_year; 

	int xx=7;   // 7 = July 
	int xy=26;  // 26 = 26th of July 
	_mday=1; 
	_wday=1; 
	_moon=1; 

	while ((xx!=month) || (xy!=day)) 
	{ 
		xy++; 
		_seal++; 
		_tone++; 
		_mday++; 
		_wday++; 
		
		if (_wday>7) 
			_wday=1; 

		if (_mday>28) 
		{
			_mday=1; 
			_moon++; 
		} 
		if (_seal==20) 
			_seal=0; 

		if (_tone==14) 
			_tone=1;

		if (xy>months[xx]) 
		{ 
			xx++; 
			xy=1; 
			if (xx==13) 
				xx=1; 
		}
	 } 
	 
	 return self;
}

- (NSString *)destinyKinLabel
{
	return  [NSString stringWithCString: sseal[_seal]];
}

- (int)destinyKin
{
	return _seal;
}

- (BOOL)isPacalAuspiciousDay
{
	int i;
	
	for (i=0; i<13; i++)
		if ([self kin: _tone seal:_seal]==pacalAuspiciousDays[i]) return YES;

	return NO;
}


- (int)guideKin
{
	if (_tone==1 || _tone==6 || _tone==11)
		return _seal;
		
	if (_tone==2 || _tone==7 || _tone==12)
	{
		int guide=_seal+12; 
		if (guide>=20)  
			guide=_seal-8; 
			
		return guide;
	}
	if (_tone==3 || _tone==8 || _tone==13)
	{
		int guide=_seal+4; 
		if (guide>=20)  
			guide=_seal-16; 
		return guide;
	}
	if (_tone==4 || _tone==9)
	{
		int guide=_seal-4; 
		if (guide<0)  
			guide=_seal+16; 
		return guide;
	}
	if (_tone==5 || _tone==10)
	{
		int guide=_seal+8; 
		if (guide>=20)  
			guide=_seal-12; 
		return guide;
	}

	return 0;
}

- (NSString *)guideKinLabel
{
	return [NSString stringWithFormat: @"%s %s", tone[_tone], sseal[[self guideKin]]];
}

- (int)analogKin
{
	int kin=19-_seal;
	if (kin <0) kin=19;
	
	return kin;
}

- (NSString *)analogKinLabel
{
	return [NSString stringWithFormat: @"%s %s", tone[_tone], sseal[[self analogKin]]];
}

- (int)antipodeKin
{
	int kin=_seal+10; 
	if (kin>=20)  
		kin=_seal-10; 
		
	return kin;
}

- (NSString *)antipodeKinLabel
{
	return [NSString stringWithFormat: @"%s %s", tone[_tone], sseal[[self antipodeKin]]];
}

- (int)occultKin
{
	int kin=21-_seal;
	if (kin>=20) kin-=20;
	
	return kin;
}

- (NSString *)occultKinLabel
{
	return [NSString stringWithFormat: @"%s %s", tone[toneoccult[_tone]], sseal[[self occultKin]]];
}

- (int)tone
{
	return _tone;
}

- (int)seal
{
	return _seal;
}


- (int)kin:(int)tone seal:(int)seal
{
	int kinSealShift=seal-1;
	if (kinSealShift <0) kinSealShift=19;
	
	return kinMatrix[kinSealShift][tone-1];
}

- (int)isGAP:(int)tone seal:(int)seal
{
	int kinSealShift=seal-1;
	if (kinSealShift <0) kinSealShift=19;
	
	return gapMatrix[kinSealShift][tone-1];
}

- (BOOL)isGAP
{
	return [self isGAP:_tone seal:_seal];
}


- (NSString *)dreamspellGlyph
{
	return [NSString stringWithFormat: @"Kin %d - %s %s %s",  [self kin: _tone seal:_seal], color[_seal], tone[_tone], sseal[_seal]]; 
}

- (NSString *)dreamspellTextExport
{
	return [self dreamspellTextImpl:YES];
}

- (NSString *)dreamspellText
{
	return [self dreamspellTextImpl:NO];
}

- (NSString *)dreamspellTextImpl:(BOOL)format
{
	NSString *text;
	
	text = [NSString stringWithFormat: @"I %s in order to %s", toneseal[_tone], poemseal[_seal]];
	text = [NSString stringWithFormat:(format ? @"%@\\n" : @"%@\n"), text];
	text = [NSString stringWithFormat: @"%@%s %s", text, toneseal2[_tone], poemseal2[_seal]];
	text = [NSString stringWithFormat:(format ? @"%@\\n" : @"%@\n"), text];
	text = [NSString stringWithFormat: @"%@I seal the %s of %s", text, poemseal3[_seal], poemseal4[_seal]];
	text = [NSString stringWithFormat:(format ? @"%@\\n" : @"%@\n"), text];
	text = [NSString stringWithFormat: @"%@With the %s tone of %s", text, tone[_tone], toneseal3[_tone]];
	text = [NSString stringWithFormat:(format ? @"%@\\n" : @"%@\n"), text];
	int guide=[self guideKin];
	
	if (guide==_seal)
		text = [NSString stringWithFormat: @"%@I am guided by my own power doubled", text];
	else
		text = [NSString stringWithFormat: @"%@I am guided by the power of %s", text, poemseal4[guide]];

	text = [NSString stringWithFormat:(format ? @"%@\\n" : @"%@\n"), text];

	return text;
}

- (NSString *)moonDay
{
	if (_moon==14) 
		return [NSString stringWithFormat: @"This is the day out of time"];
	else 
		return [NSString stringWithFormat: @"%s Moon Day %d",tone[_moon], _mday];

	return nil;
}

- (NSString*)dreamspellYearText
{
	return [NSString stringWithFormat: @"%s %s %s Year",  color[_yearseal], tone[_yeartone], sseal[_yearseal]]; 
}


- (void)yearmore:(int)year
{
	 int i=year-BASEYEAR, z; 
	 for (z=1; z<=i; z++) 
	 { 
		_seal+=5; 
		_year++; 

		if (_year>=14) 
			_year=1; 

		if (_seal>=20) 
			_seal=4; 
	}
}

- (void)yearless:(int)year
{
	 int i=BASEYEAR-year, z; 
	 for (z=1; z<=i; z++) 
	 { 
		_seal-=5; 
		_year--; 

		if (_year<=0)  
			_year=13; 

		if (_seal<=3) 
			_seal=19; 
	 } 
}


- (void)dropyear
{
	 _seal-=5; 
	 _year--;
	  
	 if (_year<=0)  
		_year=13; 

	 if (_seal<=3) 
		_seal=19; 
} 

@end


/*  Generate Tzolkin Matrix
	int t,s;
	
	for (s=0; s <20; s++)
	{
		for (t=0; t <13; t++)
			printf ("%d, ",s+1+(t*20));

		printf ("\n");
	
	}

// Generate Tone Matrix

	int t,s,i;
	
	for (s=0; s <20; s++)
	{
		for (i=t=0; i <260; i++)
		{
			t++;

			if ((i%20)==s)
				printf ("%d, ",t);

			if (t>12) t=0;
		}
		printf ("\n");
	}
	
	

// Generate Kin Matrix
	int t,t2, s;
	
	for (s=0; s <20; s++)
	{
		for (t=0; t <13; t++)
		{
			for (t2=0; t2 <13; t2++)
				if (toneMatrix[s][t2]==t+1)
					printf ("%d, ",tzolkinMatrix[s][t2]);
			
		}

		printf ("\n");
	
	}


// Generate GAP Matrix

	int t,s;
	
	for (s=0; s <20; s++)
	{
		for (t=0; t <13; t++)
		{
			int i; 
			int isGap=0;
			for (i=0; i<52; i++)
			{
				if (kinMatrix[s][t]==gapDays[i])
				{
					isGap=1;
					break;
				}
			}
			printf("%d,",isGap);
		}
		printf ("\n");
	
	}




*/
